package cn.kgc.fcm.dsbank.aspect;

import cn.kgc.fcm.dsbank.controller.SysLogController;
import cn.kgc.fcm.dsbank.entity.Employee;
import cn.kgc.fcm.dsbank.entity.Syslog;
import cn.kgc.fcm.dsbank.service.SyslogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import org.springframework.validation.support.BindingAwareModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

@Component
@Aspect
public class SyslogAdvice {

    private final static Logger log = LoggerFactory.getLogger(SyslogAdvice.class);

    @Autowired
    private HttpServletRequest request;
    @Autowired
    private SyslogService syslogService;

    private Date startTime;     //访问开始时间
    private Class visitClass;   //访问的类的Class对象
    private Method visitMethod;  //访问的方法的Method对象


    //编写切入点表达式，注意这里要对Controller的方法增强
    @Pointcut("execution(* cn.kgc.fcm.dsbank.controller.*.*(..))")
    public void pt(){}

    @Before("pt()")
    public void doBefore(JoinPoint jp) throws NoSuchMethodException {
        //获取当前时间对象
        startTime = new Date();

        //获取访问的类的Class对象
        visitClass = jp.getTarget().getClass();

        //获取访问的方法的名称
        String mehtodName = jp.getSignature().getName();

        //获取访问的方法的参数
        Object[] args = jp.getArgs();

        //如果访问的方法没有参数
        if (args == null || args.length == 0){
            //通过方法名获取方法对象
            visitMethod = visitClass.getMethod(mehtodName);
        }else {
            Class[] classArgs = new Class[args.length];
            for (int i = 0; i < args.length; i++) {

                if (args[i] instanceof BindingAwareModelMap){
                    classArgs[i] = Model.class;
                    continue;
                }
                //通过遍历获取的参数数组，后去该参数的Class对象
                classArgs[i] = args[i].getClass();

            }
            visitMethod = visitClass.getMethod(mehtodName,classArgs);
        }

        log.info("通知类前置方法执行");

    }

    @After("pt()")
    public void doAfter(){
        log.info("通知类后置方法执行");

        if(visitClass != SysLogController.class){
            RequestMapping classAnnotation = (RequestMapping) visitClass.getAnnotation(RequestMapping.class);

            if (classAnnotation != null){
                RequestMapping methodAnnotation = visitMethod.getAnnotation(RequestMapping.class);

                if (methodAnnotation != null){
                    String url = "";
                    url = classAnnotation.value()[0] + methodAnnotation.value()[0];

                    //封装数据
                    Syslog syslog = new Syslog();
                    //后置方法发生的时间-前置方法发生的时间=在该方法中执行的时间
                    Long visitTime = new Date().getTime() - startTime.getTime();

                    syslog.setVisitTime(visitTime);
                    syslog.setVisitUrl(url);
                    //获取访问者的ip
                    String ipAddress = request.getRemoteAddr();
                    syslog.setIpAddress(ipAddress);

//                    //获取登录用户
//                    Employee loginedEmp = (Employee) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//
                    log.info("security容器：{}",SecurityContextHolder.getContext().getAuthentication());

                    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

                    if (null != authentication){
                        Employee emp = (Employee) authentication.getPrincipal();
                        syslog.setEmpId(emp.getEmpId());
                        syslog.setMethodName(visitClass.getName()+":"+ visitMethod.getName());

                        syslog.setOperatorTime(startTime);

                        log.info("获取的日志信息："+syslog);

                        //存入数据库
                        syslogService.addSyslog(syslog);
                    }




                }

            }

        }
    }
}
